D:\a\cssh-rs\cssh-rs\xtask\src\cross_build\mod.rs
Line | Count | Source |
1 | | //! Cross-build dispatch for cssh-rs. |
2 | | //! |
3 | | //! Single contributor-facing entry point - `cargo xtask cross-build <target>` - |
4 | | //! for producing a cssh-rs binary for any supported target from any |
5 | | //! supported host. The xtask owns the toolchain selection so the |
6 | | //! developer experience does not drift over time. |
7 | | //! |
8 | | //! [`run_cross_build`] orchestrates the workflow: host detection, |
9 | | //! Rust target install, helper-tool install, and the final build |
10 | | //! subprocess. Per-target details (strategy + I/O) live in the |
11 | | //! [`strategy`] and [`system`] submodules. |
12 | | |
13 | | pub mod strategy; |
14 | | pub mod system; |
15 | | |
16 | | use std::sync::LazyLock; |
17 | | |
18 | | use anyhow::Result; |
19 | | use clap::ValueEnum; |
20 | | use cssh_rs_meta::PACKAGE_NAME; |
21 | | |
22 | | pub use system::{CrossBuildSystem, RealSystem}; |
23 | | |
24 | | static X86_64_PC_WINDOWS_MSVC_BINARY: LazyLock<String> = |
25 | 0 | LazyLock::new(|| format!("{PACKAGE_NAME}.exe")); |
26 | | |
27 | | /// Supported cross-build target triples. |
28 | | /// |
29 | | /// v1 supports one target, `x86_64-pc-windows-msvc` (the only target |
30 | | /// cssh-rs currently ships). Adding a target later is additive: extend |
31 | | /// this enum, extend [`Target::triple`] / [`Target::binary_filename`], |
32 | | /// add a `strategy::<target>` submodule with a `build` entry point, |
33 | | /// and add a dispatch arm in [`run_cross_build`]. |
34 | | #[derive(Copy, Clone, Debug, PartialEq, Eq, ValueEnum)] |
35 | | pub enum Target { |
36 | | /// `x86_64-pc-windows-msvc` (production Windows target). |
37 | | #[value(name = "x86_64-pc-windows-msvc")] |
38 | | X86_64PcWindowsMsvc, |
39 | | } |
40 | | |
41 | | impl Target { |
42 | | /// Return the Rust target triple this variant maps to. |
43 | | /// |
44 | | /// # Returns |
45 | | /// The canonical `--target` string passed to `cargo`. |
46 | 11 | pub fn triple(self) -> &'static str { |
47 | 11 | match self { |
48 | 11 | Self::X86_64PcWindowsMsvc => "x86_64-pc-windows-msvc", |
49 | | } |
50 | 11 | } |
51 | | |
52 | | /// Return the executable filename cargo emits for this target, |
53 | | /// including any platform-specific extension (e.g. `.exe`). |
54 | 0 | pub fn binary_filename(self) -> &'static str { |
55 | 0 | match self { |
56 | 0 | Self::X86_64PcWindowsMsvc => X86_64_PC_WINDOWS_MSVC_BINARY.as_str(), |
57 | | } |
58 | 0 | } |
59 | | } |
60 | | |
61 | | /// Cross-build cssh-rs for the given target. |
62 | | /// |
63 | | /// # Arguments |
64 | | /// * `system` - Injected I/O provider. |
65 | | /// * `target` - The user-selected target. |
66 | | /// * `release` - When true, build with `--release`; otherwise debug. |
67 | | /// |
68 | | /// # Errors |
69 | | /// Returns an error if the (host, target) pair is unsupported, a |
70 | | /// toolchain install fails, or the build subprocess fails. |
71 | 10 | pub fn run_cross_build<S>(system: &S, target: Target, release: bool) -> Result<()> |
72 | 10 | where |
73 | 10 | S: system::windows_msvc::WindowsMsvcSystem, |
74 | | { |
75 | 10 | let host = system.host_os(); |
76 | 10 | let triple = target.triple(); |
77 | 10 | let profile = if release { "release"2 } else { "debug"8 }; |
78 | 10 | log::info!("Cross-building {triple} from {host} host ({profile} profile)"); |
79 | | |
80 | 10 | match target { |
81 | 10 | Target::X86_64PcWindowsMsvc => strategy::windows_msvc::build(system, release)?3 , |
82 | | } |
83 | | |
84 | 7 | log::info!( |
85 | | "Binary built: target/{triple}/{profile}/{}", |
86 | 0 | target.binary_filename() |
87 | | ); |
88 | 7 | Ok(()) |
89 | 10 | } |
90 | | |
91 | | /// Ensure the given Rust target triple is installed via rustup. |
92 | | /// |
93 | | /// Shared by every per-target strategy; install is a single |
94 | | /// `rustup target add` if the triple is not already listed. |
95 | 9 | pub(crate) fn ensure_rust_target_installed<S: CrossBuildSystem>( |
96 | 9 | system: &S, |
97 | 9 | triple: &str, |
98 | 9 | ) -> Result<()> { |
99 | 9 | let installed = system.list_installed_targets()?0 ; |
100 | 9 | if installed.lines().any(|line| line.trim() == triple) { |
101 | 8 | log::info!("Rust target {triple} already installed"); |
102 | | } else { |
103 | 1 | log::info!("Installing Rust target {triple}"); |
104 | 1 | system.install_target(triple)?0 ; |
105 | | } |
106 | 9 | Ok(()) |
107 | 9 | } |
108 | | |
109 | | #[cfg(test)] |
110 | | #[path = "../tests/test_cross_build.rs"] |
111 | | mod tests; |